package com.jevons.geo_lib.manager;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.PointF;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.jevons.geo_lib.R;
import com.jevons.geo_lib.helper.SymbolGenerator;
import com.jevons.geo_lib.utils.StringUtils;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
import com.mapbox.geojson.LineString;
import com.mapbox.geojson.Point;
import com.mapbox.geojson.Polygon;
import com.mapbox.mapboxsdk.annotations.BubbleLayout;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.plugins.annotation.Symbol;
import com.mapbox.mapboxsdk.plugins.annotation.SymbolManager;
import com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions;
import com.mapbox.mapboxsdk.style.expressions.Expression;
import com.mapbox.mapboxsdk.style.layers.FillLayer;
import com.mapbox.mapboxsdk.style.layers.LineLayer;
import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.turf.TurfConstants;
import com.mapbox.turf.TurfMeasurement;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;

/**
 * Copyright 2020 JxGIS
 *
 * @file MeasureManager
 * @auth linaisheng
 * Created on 2024/7/31.
 * Description：
 */
public class MeasureManager {

    public enum MeasureType {

        None,
        MeasureDistance,
        MeasureArea,
        LandAnalysis;

    }

    public enum DistanceUnit {
        METERS,
        KILOMETERS
    }

    public enum AreaUnit {
        MU,         //亩
        HECTARE    //公顷
    }


    //测量绘图
    public static final String MEASURE_ANALYSIS_SOURCE = "measure_analysis_layer_source";
    public static final String MEASURE_ANALYSIS_FILL_LAYER = "measure_analysis_fill";
    public static final String MEASURE_ANALYSIS_LINE_LAYER = "measure_analysis_line";

    //地图打点
    private static final String ICON_MEASURE_POINT = "icon_measure_point";
    //临时浮窗
    private static final String MEASURE_DATA_INFO_WINDOW = "measureDataInfoWindow";

    private static final String KEY_PROPERTY_ID = "id";
    private static final String KEY_PROPERTY_IS_POLYGON = "isPolygon";
    private static final String KEY_PROPERTY_IS_COMPLETE = "isComplete";
    private static final String KEY_PROPERTY_VALUE_TEXT = "valueText";

    private static final String KEY_PROPERTY_IS_LAND_ANALYSIS = "isLandAnalysis";
    private static final String KEY_PROPERTY_LAND_ANALYSIS_ID = "analysisId";

    private static final String KEY_PROPERTY_COLOR = "color";

    private static final String KEY_PROPERTY_MEASURE_TYPE = "measureType";
    private static final String KEY_PROPERTY_MEASURE_TYPE_DISTANCE = "measureTypeDistance";
    private static final String KEY_PROPERTY_MEASURE_TYPE_AREA = "measureTypeArea";
    private static final String KEY_PROPERTY_MEASURE_TYPE_LAND_ANALYSIS = "measureTypeLandAnalysis";

    private MapView mMapView;
    private MapboxMap mMapboxMap;
    private Style loadStyle;
    private SymbolManager symbolManager;

    private GeoJsonSource measureAnalysisSource;
    private FeatureCollection measureFeatureCollection = FeatureCollection.fromFeatures(new ArrayList<>());
    private List<Symbol> measureMarkerList = new ArrayList<>();
    private HashMap<String, Symbol> symbolWindowsMap = new HashMap<>();

    private MeasureType measureType = MeasureType.None;

    private DistanceUnit distanceUnit = DistanceUnit.METERS;
    private AreaUnit areaUnit = AreaUnit.MU;

    public MeasureManager(MapView mapView, MapboxMap mapboxMap, Style style) {
        this(mapView, mapboxMap, style, null);
    }

    public MeasureManager(MapView mapView, MapboxMap mapboxMap, Style style, SymbolManager symbolManager) {
        this.mMapView = mapView;
        this.mMapboxMap = mapboxMap;
        this.loadStyle = style;
        if (symbolManager != null) {
            this.symbolManager = symbolManager;
        } else {
            this.symbolManager = new SymbolManager(mapView, mapboxMap, style);
        }
        this.symbolManager.setIconIgnorePlacement(true);
    }


    public void addMeasureLayerAbove(String aboveId) {
        measureAnalysisSource = new GeoJsonSource(MEASURE_ANALYSIS_SOURCE);
        loadStyle.addSource(measureAnalysisSource);

        FillLayer fillLayer = new FillLayer(MEASURE_ANALYSIS_FILL_LAYER, MEASURE_ANALYSIS_SOURCE)
                .withFilter(Expression.has(KEY_PROPERTY_IS_POLYGON))
                .withProperties(
                        PropertyFactory.fillColor(Expression.switchCase(
                                Expression.has(KEY_PROPERTY_COLOR), Expression.toColor(Expression.get(KEY_PROPERTY_COLOR)),
                                Expression.color(Color.parseColor("#FF8000"))
                        )),
                        PropertyFactory.fillOpacity(0.6f)
                );
        loadStyle.addLayerAbove(fillLayer, aboveId);

        LineLayer lineLayer = new LineLayer(MEASURE_ANALYSIS_LINE_LAYER, MEASURE_ANALYSIS_SOURCE);
        lineLayer.withProperties(
                PropertyFactory.lineColor(
                        Expression.switchCase(
                                Expression.has(KEY_PROPERTY_COLOR), Expression.toColor(Expression.get(KEY_PROPERTY_COLOR)),
                                Expression.color(Color.parseColor("#FF8000"))
                        )),
                PropertyFactory.lineWidth(3f)
        );
        loadStyle.addLayerAbove(lineLayer, MEASURE_ANALYSIS_FILL_LAYER);

        loadStyle.addImage(ICON_MEASURE_POINT,
                Bitmap.createBitmap(BitmapFactory.decodeResource(
                        mMapView.getResources(), R.mipmap.icon_map_point)));
    }


    public void setMeasureType(MeasureType measureType) {
        this.measureType = measureType;
    }

    public MeasureType getMeasureType() {
        return measureType;
    }

    public void onMeasureClickMap(LatLng latLng) {
        Symbol symbol = symbolManager.create(
                new SymbolOptions().withLatLng(latLng)
                        .withIconImage(ICON_MEASURE_POINT)
                        .withIconSize(1f)
                        .withDraggable(false));
        measureMarkerList.add(symbol);

        if (measureMarkerList.size() > 1) {
            dealMeasure();
        }

    }

    private void dealMeasure() {
        //每次删除最后一个编辑的Feature
        if (measureFeatureCollection.features().size() > 0) {

            Feature lastFeature = measureFeatureCollection.features().get(
                    measureFeatureCollection.features().size() - 1);

            if (!lastFeature.hasProperty(KEY_PROPERTY_IS_COMPLETE)) {
                //删除未完成的图像
                measureFeatureCollection.features().remove(
                        measureFeatureCollection.features().size() - 1);
            }
        }

        List<Point> points = new ArrayList<>();

        for (int i = 0; i < measureMarkerList.size(); i++) {
            LatLng item = measureMarkerList.get(i).getLatLng();
            Point point = Point.fromLngLat(item.getLongitude(), item.getLatitude());
            points.add(point);
        }


        Feature feature;
        Symbol tempSymbol = symbolWindowsMap.get(MEASURE_DATA_INFO_WINDOW);
        JsonObject jsonObject = new JsonObject();
        LatLng symbolLatlng = null;
        if (measureType == MeasureType.MeasureArea) {


            points.add(points.get(0));
            List<List<Point>> data = new ArrayList<>();
            data.add(points);
            feature = Feature.fromGeometry(Polygon.fromLngLats(data));
            feature.addBooleanProperty(KEY_PROPERTY_IS_POLYGON, true);
            //测量面积
            double area = TurfMeasurement.area(feature);

            if (areaUnit == AreaUnit.MU) {
                area = area * 0.0015;
            } else {
                area = area / 10000d;
            }

            Point centerPoint = (Point) TurfMeasurement.center(feature).geometry();
            symbolLatlng = new LatLng(centerPoint.latitude(), centerPoint.longitude());

            String unitText = areaUnit ==AreaUnit.MU ? "亩" : "公顷";
            String valueText = String.format("%.2f", area) + unitText;
            loadStyle.addImage(MEASURE_DATA_INFO_WINDOW,
                    generateBitmap(valueText));

            jsonObject.add(KEY_PROPERTY_ID, new JsonPrimitive(generateId()));
            jsonObject.add(KEY_PROPERTY_VALUE_TEXT, new JsonPrimitive(valueText));
            jsonObject.add(KEY_PROPERTY_MEASURE_TYPE, new JsonPrimitive(KEY_PROPERTY_MEASURE_TYPE_AREA));
        } else if (measureType == MeasureType.MeasureDistance) {
            symbolLatlng = measureMarkerList.get(measureMarkerList.size() - 1).getLatLng();
            LineString lineString = LineString.fromLngLats(points);
            feature = Feature.fromGeometry(lineString);
            String unit = TurfConstants.UNIT_METERS;
            if (distanceUnit == DistanceUnit.KILOMETERS) {
                unit = TurfConstants.UNIT_KILOMETERS;
            }
            double distance = TurfMeasurement.length(lineString, unit);

            String unitText = distanceUnit == DistanceUnit.METERS ? "米" : "千米";
            String valueText = String.format("%.2f", distance) + unitText;
            loadStyle.addImage(MEASURE_DATA_INFO_WINDOW,
                    generateBitmap(valueText));

            jsonObject.add(KEY_PROPERTY_ID, new JsonPrimitive(generateId()));
            jsonObject.add(KEY_PROPERTY_VALUE_TEXT, new JsonPrimitive(valueText));
            jsonObject.add(KEY_PROPERTY_MEASURE_TYPE, new JsonPrimitive(KEY_PROPERTY_MEASURE_TYPE_DISTANCE));
        } else {
            points.add(points.get(0));
            List<List<Point>> data = new ArrayList<>();
            data.add(points);
            feature = Feature.fromGeometry(Polygon.fromLngLats(data));

            jsonObject.add(KEY_PROPERTY_ID, new JsonPrimitive(generateId()));
            feature.addBooleanProperty(KEY_PROPERTY_IS_POLYGON, true);
            jsonObject.add(KEY_PROPERTY_MEASURE_TYPE, new JsonPrimitive(KEY_PROPERTY_MEASURE_TYPE_LAND_ANALYSIS));
        }

        measureFeatureCollection.features().add(feature);
        measureAnalysisSource.setGeoJson(measureFeatureCollection);

        if (tempSymbol != null && symbolLatlng != null) {
            tempSymbol.setLatLng(symbolLatlng);
            tempSymbol.setData(jsonObject);
            symbolManager.update(tempSymbol);
        } else {
            if (measureType == MeasureType.LandAnalysis) {
                return;
            } else if (measureType == MeasureType.MeasureArea
                    && measureMarkerList.size() <= 2) {
                return;
            }
            symbolWindowsMap.put(MEASURE_DATA_INFO_WINDOW,
                    symbolManager.create(
                            new SymbolOptions().withLatLng(symbolLatlng)
                                    .withData(jsonObject)
                                    .withIconImage(MEASURE_DATA_INFO_WINDOW)
                                    .withIconOffset(new Float[]{-2f, -24f})));
        }

    }


    public void setDistanceUnit(DistanceUnit unit) {
        distanceUnit = unit;
    }

    public DistanceUnit getDistanceUnit() {
        return distanceUnit;
    }

    public void setAreaUnit(AreaUnit unit) {
        areaUnit = unit;
    }


    public AreaUnit getAreaUnit() {
        return areaUnit;
    }

    public void undoMeasure() {
        if (measureMarkerList.size() > 0) {
            Symbol symbol = measureMarkerList.remove(measureMarkerList.size() - 1);
            symbolManager.delete(symbol);
            boolean canCompleteMeasure = (measureType == MeasureType.MeasureDistance && measureMarkerList.size() > 1) ||
                    (measureType == MeasureType.MeasureArea && measureMarkerList.size() > 2) ||
                    (measureType == MeasureType.LandAnalysis && measureMarkerList.size() > 2);
            if (canCompleteMeasure) {
                dealMeasure();
            } else {
                loadStyle.removeImage(MEASURE_DATA_INFO_WINDOW);
                Symbol tempSymbol = symbolWindowsMap.remove(MEASURE_DATA_INFO_WINDOW);
                if (tempSymbol != null) {
                    symbolManager.delete(tempSymbol);
                }
                //删除最后一个编辑的Feature
                if (measureFeatureCollection.features().size() > 0) {

                    Feature lastFeature = measureFeatureCollection.features().get(
                            measureFeatureCollection.features().size() - 1);

                    if (!lastFeature.hasProperty(KEY_PROPERTY_IS_COMPLETE)) {
                        //删除未完成的图像
                        measureFeatureCollection.features().remove(
                                measureFeatureCollection.features().size() - 1);
                    }
                }
                measureAnalysisSource.setGeoJson(measureFeatureCollection);
            }
        }
    }

    public void clearCurrentMeasureData() {
        //清除正在标绘数据
        symbolManager.delete(measureMarkerList);
        measureMarkerList.clear();
        if (measureType == MeasureType.MeasureDistance
                || measureType == MeasureType.MeasureArea) {

            loadStyle.removeImage(MEASURE_DATA_INFO_WINDOW);
            Symbol tempSymbol = symbolWindowsMap.remove(MEASURE_DATA_INFO_WINDOW);
            if (tempSymbol != null) {
                symbolManager.delete(tempSymbol);
            }
        }

        if (measureFeatureCollection.features().size() > 0) {
            Feature lastFeature = measureFeatureCollection.features().get(
                    measureFeatureCollection.features().size() - 1);

            if (!lastFeature.hasProperty(KEY_PROPERTY_IS_COMPLETE)) {
                //删除未完成的图像
                measureFeatureCollection.features().remove(
                        measureFeatureCollection.features().size() - 1);
            }
            measureAnalysisSource.setGeoJson(measureFeatureCollection);
        }
    }

    public void clearMeasureLayer() {
        //清除正在标绘数据
        symbolManager.delete(measureMarkerList);
        measureMarkerList.clear();

        symbolManager.delete(new ArrayList<>(symbolWindowsMap.values()));
        for (String key : symbolWindowsMap.keySet()) {
            loadStyle.removeImage(key);
        }
        symbolWindowsMap.clear();

        measureFeatureCollection.features().clear();
        measureAnalysisSource.setGeoJson(measureFeatureCollection);
    }

    public Feature saveCurrentMeasure() {
        if ((measureType == MeasureType.MeasureDistance && measureMarkerList.size() > 1) ||
                (measureType == MeasureType.MeasureArea && measureMarkerList.size() > 2) ||
                (measureType == MeasureType.LandAnalysis && measureMarkerList.size() > 2)) {
            symbolManager.delete(measureMarkerList);
            measureMarkerList.clear();

            loadStyle.removeImage(MEASURE_DATA_INFO_WINDOW);
            Symbol tempSymbol = symbolWindowsMap.remove(MEASURE_DATA_INFO_WINDOW);
            if (tempSymbol != null) {
                symbolManager.delete(tempSymbol);

                JsonObject data = (JsonObject) tempSymbol.getData();
                String key = generateId();

                loadStyle.addImage(key,
                        generateBitmap(data.get(KEY_PROPERTY_VALUE_TEXT).getAsString()));

                symbolWindowsMap.put(key,
                        symbolManager.create(
                                new SymbolOptions().withLatLng(tempSymbol.getLatLng())
                                        .withData(data)
                                        .withIconImage(key)
                                        .withIconOffset(new Float[]{-2f, -20f})));
            }

            Feature saveFeature = measureFeatureCollection.features().get(
                    measureFeatureCollection.features().size() - 1);
            if (measureType == MeasureType.MeasureDistance || measureType == MeasureType.MeasureArea) {
                //标记完成
                saveFeature.addBooleanProperty(KEY_PROPERTY_IS_COMPLETE, true);
            }

            return saveFeature;
        }
        return null;
    }


    public void setLandReferResult(String measureFeatureId, String key, List<Feature> referFeatureList) {
        if (measureFeatureCollection.features().size() > 0) {
            for (Feature feature : measureFeatureCollection.features()) {
                String id = feature.getStringProperty(KEY_PROPERTY_ID);
                if (StringUtils.isNotEmpty(measureFeatureId) && measureFeatureId.equals(id)) {
                    feature.addBooleanProperty(KEY_PROPERTY_IS_COMPLETE, true);
                    feature.addBooleanProperty(KEY_PROPERTY_IS_LAND_ANALYSIS, true);
                    feature.addStringProperty(KEY_PROPERTY_LAND_ANALYSIS_ID, key);
                }
            }
        }


        for (Feature feature : referFeatureList) {
            feature.addBooleanProperty(KEY_PROPERTY_IS_COMPLETE, true);
            feature.addBooleanProperty(KEY_PROPERTY_IS_POLYGON, true);
            feature.addBooleanProperty(KEY_PROPERTY_IS_LAND_ANALYSIS, true);
            feature.addStringProperty(KEY_PROPERTY_LAND_ANALYSIS_ID, key);
            feature.addStringProperty(KEY_PROPERTY_COLOR, "#1366db");

            measureFeatureCollection.features().add(feature);
        }
        measureAnalysisSource.setGeoJson(measureFeatureCollection);
    }

    public String queryLandReferData(LatLng point) {
        if (loadStyle.getLayer(MEASURE_ANALYSIS_FILL_LAYER) != null) {
            PointF pointF = mMapboxMap.getProjection().toScreenLocation(point);
            List<Feature> features = mMapboxMap.queryRenderedFeatures(pointF, MEASURE_ANALYSIS_FILL_LAYER);
            if (features.size() == 0) {
                return null;
            }
            for (Feature feature : features) {
                if (feature.hasProperty(KEY_PROPERTY_IS_LAND_ANALYSIS)) {
                    return feature.getStringProperty(KEY_PROPERTY_LAND_ANALYSIS_ID);
                }
            }
        }
        return null;
    }

    private Bitmap generateBitmap(String text) {
        BubbleLayout bubbleLayout = (BubbleLayout)
                LayoutInflater.from(mMapView.getContext()).inflate(R.layout.view_measure_info_window, null);

        TextView titleTextView = bubbleLayout.findViewById(R.id.info_window_title);
        titleTextView.setText(text);

        int measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        bubbleLayout.measure(measureSpec, measureSpec);

        float measuredWidth = bubbleLayout.getMeasuredWidth();

        bubbleLayout.setArrowPosition(measuredWidth / 2 - 5);

        return SymbolGenerator.generate(bubbleLayout);
    }

    private String generateId() {
        return UUID.randomUUID().toString().replace("-", "");
    }

}